////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2016-2018 Qualcomm Technologies, Inc.
// All Rights Reserved.
// Confidential and Proprietary - Qualcomm Technologies, Inc.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @file  camxnode.h
/// @brief Node class declaration
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef CAMXNODE_H
#define CAMXNODE_H

#include "camxthreadmanager.h" // doesn't belong here...just a bigger rabbit hole to remove at the moment
#include "camxpipeline.h"

#include "chinode.h"

struct ChiStream;
struct ChiPipelineInputOptions;
struct ChiTuningModeParameter;

CAMX_NAMESPACE_BEGIN

/// Forward Declarations

enum class Format;

class  ChiContext;
class  HwFactory;
class  ImageBuffer;
class  MetadataPool;
class  Node;
class  Pipeline;
class  TuningDataManager;
class  ImageBufferManager;
class  CmdBuffer;
class  CmdBufferManager;

struct BufferPropertiesInfo;
struct CaptureRequest;
struct ChiFence;
struct FinalizeInitializationData;
struct LinkPropertiesInfo;
struct NodeInfo;
struct OutputPort;
struct PerBatchedFrameInfo;
struct PerNodeInfo;
struct ResourceParams;
struct WatermarkPattern;

static const UINT32 MaxDstPortsPerLink          = 8;
static const UINT32 MaxRequestQueueDepth        = RequestQueueDepth + 2;
static const UINT32 MaxRequestBufferDepth       = 64;
static const UINT32 MaxTuningModeSelectors      = 10;
static const UINT32 BufferCountForRealTimeNodes = 2;
static const UINT32 BufferCountForIFE           = 4;
static const SIZE_T InvalidImageBuffer          = 0xFFFFFFFF;
static const UINT32 NumProcReqData              = MaxRequestQueueDepth;    ///< Count of old requests to queue

/// @brief Structure for Output buffer for dependency buffer or delayed buffer
struct DelayedOutputBufferInfo
{
    CSLFence        hFence;                           ///< Fence associated with all Imagebuffers in the output
                                                      ///  for delayed buffer
    BOOL            isParentInputBuffer;              ///< is the image buffer a parent's input buffer
    ImageBuffer*    pImageBuffer[MaxBatchedFrames];   ///< image buffer pointers
    UINT32          sequenceId;                       ///< Sequence ID that this buffer is associated with
};

/// @brief A property dependency type
struct PropertyDependency
{
    UINT32      count;                              ///< Number of properties in this unit
    PropertyID  properties[MaxProperties];          ///< Property dependencies in this unit
    UINT64      offsets[MaxProperties];             ///< Offset from current request for dependency
    BOOL        negate[MaxProperties];              ///< Indicate if offsets are negative value
    UINT        pipelineIds[MaxProperties];         ///< Pipeline index for every Property
};

/// @brief A unit of dependency that Node reports back to Pipeline
struct DependencyUnit
{
    union
    {
        struct
        {
            UINT32 hasBufferDependency   :  1;          ///< Node reports buffer dependency
            UINT32 hasPropertyDependency :  1;          ///< Node reports property dependency
            UINT32 hasFenceDependency    :  1;          ///< Node reports Chi Fence dependency
            UINT32 isPreemptable         :  1;          ///< Can dependency be preempted
            UINT32 reserved              : 28;          ///< Reserved
        };
        UINT32 dependencyFlagsMask;                     ///< Flag mask Value
    } dependencyFlags;

    PropertyDependency propertyDependency;              ///< Set of Property dependency units

    struct
    {
        UINT      fenceCount;                           ///< Number of fences to wait for
        CSLFence* phFences[MaxDependentFences];         ///< Fences to wait for
        UINT*     pIsFenceSignaled[MaxDependentFences]; ///< Fence signal status
    } bufferDependency;                                 ///< Buffer dependency unit

    struct
    {
        UINT                chiFenceCount;                           ///< Number of fences to wait for
        ChiFence*           pChiFences[MaxDependentFences];          ///< Fences to wait for
        BOOL*               pIsChiFenceSignaled[MaxDependentFences]; ///< Fence signal status
        PFNCHIFENCECALLBACK pChiFenceCallback;                       ///< Callback when all Chi fence dependencies satisfied
        VOID*               pUserData;                               ///< Client-provided data pointer for Chi callback
    } chiFenceDependency;                                            ///< Buffer dependency unit

    INT32 processSequenceId; ///< SequenceId to provide back to node when dependency satisfied
};

/// @brief Node create input data
struct NodeCreateInputData
{
    const PerNodeInfo*           pNodeInfo;            ///< Node info
    Camera3Stream**              ppCamera3Streams;     ///< Camera3 streams
    Pipeline*                    pPipeline;            ///< Pipeline pointer
    UINT                         pipelineNodeIndex;    ///< This node instance's index in the pipeline nodes
    const HwFactory*             pFactory;             ///< HwFactory pointer
    ChiContext*                  pChiContext;          ///< Chi Context
    ChiNodeCallbacks*            pChiNodeCallbacks;    ///< CHINode callbacks pointer
    CHIAFALGORITHMCALLBACKS*     pAFAlgoCallbacks;     ///< Algo Calllback Interface for Chi
    CHIAECALGORITHMCALLBACKS*    pAECAlgoCallbacks;    ///< Algo Calllback Interface for Chi
    CHIAWBALGORITHMCALLBACKS*    pAWBAlgoCallbacks;    ///< Algo Calllback Interface for Chi
    CHIAFDALGORITHMCALLBACKS*    pAFDAlgoCallbacks;    ///< Algo Calllback Interface for Chi
    CHIASDALGORITHMCALLBACKS*    pASDAlgoCallbacks;    ///< Algo Calllback Interface for Chi
    CHIPDLIBRARYCALLBACKS*       pPDLibCallbacks;      ///< Algo Calllback Interface for Chi
    CHIISPHVXALGORITHMCALLBACKS* pHVXAlgoCallbacks;    ///< HVX Algo Callback Interface for Chi
};

/// @brief NodeCreateFlags flags
union NodeCreateFlags
{
    struct
    {
        BIT isSinkBuffer                    : 1;  ///< Node with a sink port that outputs a buffer
        BIT isSinkNoBuffer                  : 1;  ///< Node with a sink port that does not output a buffer
        BIT isSourceBuffer                  : 1;  ///< Node who has a input port that is not connected to any other node
        BIT isInPlace                       : 1;  ///< Is this an in place node whose output buffer is the same as input buffer
        BIT willNotifyConfigDone            : 1;  ///< Node needs to notify config done
        BIT isBypassable                    : 1;  ///< Is node a bypassable node
        BIT canDRQPreemptOnStopRecording    : 1;  ///< Can DRQ preempt node on recording stop/pause
        BIT reserved                        : 25; ///< Reserved
    };

    UINT value;
};

/// @brief Node create output data
struct NodeCreateOutputData
{
    Node*            pNode;                                ///< Created node object pointer
    const CHAR*      pNodeName;                            ///< Name of the node (filled in the by the derived node)
    NodeCreateFlags  createFlags;                          ///< Create flags
    UINT             maxNumCmdBufferManagers;              ///< Max require number of command buffer managers
    UINT             maxOutputPorts;                       ///< Max number of output ports supported
    UINT             maxInputPorts;                        ///< Max number of input ports supported
};

/// @brief Node capture request data.
struct NodeProcessRequestData
{
    CaptureRequest*      pCaptureRequest;                    ///< Stream configuration pointer
    DependencyUnit       dependencyInfo[MaxDependencies];    ///< List of Dependency info that will be reported back
                                                             ///  to topology. Each element in the list is a set of
                                                             ///  property and buffer dependencies
    UINT                 numDependencyLists;                 ///  Number of entries in the Dependency List
    PerBatchedFrameInfo* pPerBatchedFrameInfo;               ///< Per batched frame info
    INT32                processSequenceId;                  ///< Identifier for the node to track its processing order
};

/// @brief Output buffer info
struct FenceHandlerBufferInfo
{
    ImageBuffer*    pImageBuffer;                       ///< ImageBuffer for the output buffer
    UINT32          sequenceId;                         ///< Sequence ID that this buffer is associated with
    BufferHandle*   phNativeHandle;                     ///< HAL buffer (valid only for output buffer on a sink port)
};

/// @brief Passed to CSL when registering fence callback. CSL passes this back in the fence callback. The fence callback
///        simply invokes the Node* and passes it the pNodePrivateData. Nodes fence handler processes the fence signal.
struct FenceCallbackData
{
    Node* pNode;            ///< Node to which the fence (being signaled) belongs to
    VOID* pNodePrivateData; ///< Node private data - Pointer to "struct PortFenceData"
};

/// @brief Node fence handler data - CSL fence callback function passes this data to the Node fence handler that processes
///        the fence signal
struct NodeFenceHandlerData
{
    FenceCallbackData       nodeCSLFenceCallbackData;            ///< Private data passed to CSL when registering
                                                                 ///  node fence callback
    OutputPort*             pOutputPort;                         ///< Output port to which this fence/imagebuffers
                                                                 ///  belong to
    UINT64                  requestId;                           ///< Request Id that this fence is associated with
    CSLFence                hFence;                              ///< Fence associated with the port
    BOOL                    isDelayedBufferFence;                ///< Is the fence for delayed output
    UINT                    isFenceSignaled;                     ///< Atomic Load/Store - Has the fence already been
                                                                 ///  signaled
    UINT                    numOutputBuffers;                    ///< Number of output buffers
    FenceHandlerBufferInfo  outputBufferInfo[MaxBatchedFrames];  ///< Info related to the output buffer on the port
    DelayedOutputBufferInfo delayedOutputBufferData;             ///< Output buffer info for bypassable node
    CSLFenceResult          fenceResult;                         ///< Fence result
};

/// @brief Bufferproperties structure that is initialized by looking at the corresponding XML structure
struct BufferProperties
{
    ImageFormat   imageFormat;                      ///< Buffer format info
    UINT          immediateAllocImageBuffers;       ///< Initial number of image buffers to be allocated
    UINT          maxImageBuffers;                  ///< Maximum number of image buffers can be allocated
    UINT          memFlags;                         ///< Memory flags
    CSLBufferHeap bufferHeap;                       ///< Buffer heap
};

/// @brief Buffer manager create data.
struct BufferManagerCreateData
{
    BufferProperties*    pBufferProperties;             ///< Buffer properties
    const INT32*         pDeviceIndices;                ///< Pointer to array of device indices that may access this buffer.
    UINT                 deviceCount;                   ///< The number of valid entries in the pDeviceIndices array.
    BOOL                 allocateBufferMemory;          ///< Boolean indicating whether buffer memory should be allocated.
    UINT                 numBatchedFrames;              ///< Greater than 1 for a link that has batch mode enabled, otherwise it
                                                        ///  MUST be set to 1
    UINT                 immediateAllocBufferCount;     ///< Number of buffers to be allocated immediately
    UINT                 maxBufferCount;                ///< Maximum number of buffers to be allocated
    ImageBufferManager*  pImageBufferManager;           ///< Created image buffer manager pointer
};

/// @brief This structure contains the buffer requirements
struct BufferRequirement
{
    UINT32        minWidth;                         ///< Min width that the node requires to generate its final output buffer
    UINT32        minHeight;                        ///< Min height that the node requires to generate its final output buffer
    UINT32        maxWidth;                         ///< Max width that the node requires to generate its final output buffer
    UINT32        maxHeight;                        ///< Max height that the node requires to generate its final output buffer
    UINT32        optimalWidth;                     ///< Optimal width that the node would want on its input buffer
    UINT32        optimalHeight;                    ///< Optimal height that the node would want on its input buffer
    AlignmentInfo planeAlignment[FormatsMaxPlanes]; ///< Stride and scanline alignment for each plane
};

/// @brief This structure contains the buffer requirements of the input ports on a node
struct PortBufferOptions
{
    UINT32            nodeId;               ///< Node Id
    UINT32            instanceId;           ///< Node instance Id
    UINT32            portId;               ///< Port Id
    BufferRequirement bufferRequirement;    ///< Buffer requirement
};

/// @brief Negotiation data for the input ports
struct InputPortNegotiationData
{
    UINT               inputPortId;                              ///< Input portId
    const ImageFormat* pImageFormat;                             ///< Image format locked down by the parent's output port
};

/// @brief Negotiation data for the output buffer per output port
struct OutputPortNegotiationData
{
    UINT               outputPortIndex;                           ///< Output port index
    BufferRequirement  inputPortRequirement[MaxDstPortsPerLink];  ///< Buffer requirement requested by the input ports
                                                                  ///  connected to the outputPort
    UINT               numInputPortsNotification;                 ///< Number of input ports that have provided their buffer
                                                                  ///  requirements for this outputPort
    BufferRequirement  outputBufferRequirementOptions;            ///< Valid options from which the final buffer properties
                                                                  ///  must be set
    BufferProperties*  pFinalOutputBufferProperties;              ///< Final output buffer properties decided after receiving
                                                                  ///  buffer requirements of all input ports connected to this
                                                                  ///  outputPort
};

/// @brief Structure that contains negotiation data for the node
struct BufferNegotiationData
{
    OutputPortNegotiationData* pOutputPortNegotiationData;              ///< Array of negotiation data per output port. Filled
                                                                        ///  on the walk-back from sink-to-source
    InputPortNegotiationData*  pInputPortNegotiationData;               ///< Array of negotiation data per input port. Filled
                                                                        ///  on the walk-forward from source-to-sink
    UINT                       numOutputPortsNotified;                  ///< Output ports whose requirements have been obtained
    UINT                       numInputPorts;                           ///< Number of input ports
    PortBufferOptions          inputBufferOptions[MaxPipelineInputs];   ///< Valid options for input port buffer
};

/// @brief OutputPort flags
union OutputPortFlags
{
    struct
    {
        BIT isBatchMode               : 1;  ///< Is batch mode enabled
        BIT isNonSinkHALBufferOutput  : 1;  ///< Flag to indicate that the output port is not a sinkport but still outputs a
                                            ///  HAL buffer. This will happen in cases if the output port is connected to an
                                            ///  inplace node that outputs a HAL buffer.
        BIT isSinkBuffer              : 1;  ///< Is it a sink port with output buffer
        BIT isSinkNoBuffer            : 1;  ///< Is it a sink port with no output buffer
        BIT isEnabled                 : 1;  ///< Is the port enabled
        BIT isSecurePort              : 1;  ///< Is the port is secure/Non-secure
        BIT isLoopback                : 1;  ///< Is it a loopback port connected to the same node
        BIT reserved                  : 25; ///< Reserved
    };

    UINT value;
};

/// @brief InputPort flags
union InputPortFlags
{
    struct
    {
        UINT isEnabled           : 1;            ///< Is the port enabled
        UINT isSourceBuffer      : 1;            ///< Is it a source port with a HAL buffer
        UINT isLoopback          : 1;            ///< Is it a loopback port connected to the same node
        UINT isParentInputBuffer : 1;            ///< Is it a parent's input buffer
        UINT isBypssablePort     : 1;            ///< Is this port can be bypassed
        UINT reserved            : 27;           ///< Reserved
    };

    UINT value;
};

/// @brief Output port structure for single output port related information
struct OutputPort
{
    UINT                  portId;                            ///< Port id (from topology XML file)
    INT32                 deviceIndices[CamxMaxDeviceIndex]; ///< Device indices that may be access buffers owned by
                                                             ///< this port
    UINT                  deviceCount;                       ///< Number of devices that is in deviceIndices list
    BufferProperties      bufferProperties;                  ///< Buffer properties
    ImageBufferManager*   pImageBufferManager;               ///< Image buffer manager pointer
    ImageBuffer**         ppImageBuffers;                    ///< Array of Image buffers(numElements == maxImageBuffers)
    NodeFenceHandlerData* pFenceHandlerData;                 ///< Array of all fence related data - one array element
                                                             ///  for one image buffer/fence
    NodeFenceHandlerData* pDelayedBufferFenceHandlerData;    ///< Array of all fence related data - one array element
                                                             ///  for one image buffer/fence
    UINT                  sinkTargetStreamId;                ///< If this is a sink port that outputs an HAL buffer,
                                                             ///  the streamId that this sink port maps to
    UINT                  enabledInStreamMask;               ///< List of Stream Ids that enable this output port
                                                             ///  Bit 0 = 1 if Stream Id 0 enables it
                                                             ///        = 0 if Stream Id 0 does not enable it
                                                             ///  Same for other stream Ids. So for e.g. if Stream 0 and
                                                             ///  Stream 2 enables this output port - the mask value
                                                             ///  would be 5
    UINT                  numInputPortsConnected;            ///< These are the number of input ports connected to this output
                                                             ///  port
    UINT                  numInputPortsDisabled;             ///< Number of input ports that do not use this output although
                                                             ///  they are connected
    BufferPropertiesInfo* pBufferProperties;                 ///< Bufferproperties coming from the XML
    UINT                  numBatchedFrames;                  ///< Number of batched frames in this output port
    OutputPortFlags       flags;                             ///< OutputPort flags
    UINT                  portSourceTypeId;                  ///< Port source type id
    UINT                  numSourcePortsMapped;              ///< Number of source Ports mapped to this output port for bypass
    UINT*                 pMappedSourcePortIds;              ///< Pointer to the source port Ids mapped to this output ports
    ChiStreamWrapper*     pChiStreamWrapper;                 ///< ChiStreamWrapper on the port
                                                             ///  for bypass
    UINT                  numInputPortsConnectedinBypass;    ///< These are the number of input ports connected to this output
                                                             ///  port through bypass
    ///@ todo (CAMX-326) Buffer manager pointers will live here and image buffers for requests will be maintained explicitly
};

/// @brief Data for all output ports
struct AllOutputPortsData
{
    UINT        numPorts;                       ///< Number of ports
    OutputPort* pOutputPorts;                   ///< Pointer to an array of output ports
    UINT        sinkPortIndices[MaxNumStreams]; ///< Array of output (SINK) port index (in the pOutputPorts array)
    UINT        numSinkPorts;                   ///< Number of sink ports
};

/// @brief Data for output port queried by clients (usually connected nodes querying each other)
struct OutputPortRequestedData
{
    ImageBuffer*             pImageBuffer;                  ///< Image buffer on the output port (for the queried request Id)
    CSLFence*                phFence;                       ///< Fence for this output port
    UINT*                    pIsFenceSignaled;              ///< Pointer to fence variable whose signaled status is checked
    DelayedOutputBufferInfo* pDelayedOutputBufferData;      ///< Delayed output buffer data
};

/// @brief Input port structure for single input port related information
struct InputPort
{
    UINT                  portId;                  ///< Port id (from topology XML file)
    Node*                 pParentNode;             ///< Parent node for triggering calls like
                                                   ///  pParentNode::GetImageBuffer(portId, requestId)
                                                   ///  The above buffer gets programmed as input buffer for
                                                   ///  the node with this input
    UINT                  parentOutputPortIndex;   ///< Parent output port to which this input port is connected port.
                                                   ///  Parent node may have an array of 'n' output ports, parentPortId tells
                                                   ///  the array element i.e. the parent output port to which this input port
                                                   ///  is connected
    UINT                  sourceTargetStreamId;    ///< If this is a source buffer port,
                                                   ///  the streamId that this source port maps to
    ImageFormat           imageFormat;             ///< Buffer image format if this input port is a source buffer port
    ImageBuffer**         ppImageBuffers;          ///< Container ImageBuffer if this input port is a source buffer port
    InputPortFlags        flags;                   ///< Flags
    CSLFence*             phFences;                ///< Input buffer fences
    UINT                  isFenceSignaled;         ///< Fence variable whose signaled status is checked
    UINT                  portSourceTypeId;        ///< Port source type id
    BOOL                  portDisabled;            ///< Input port disabled if set
    UINT64                bufferDelta;             ///< Indicates buffer requirement of current request - bufferDelta
    ImageBufferManager*   pImageBufferManager;     ///< Image buffer manager pointer
};

/// @brief Data for all input ports
struct AllInputPortsData
{
    UINT        numPorts;       ///< Number of ports
    InputPort*  pInputPorts;    ///< Pointer to an array of output ports
};

/// @brief Per request output port flags
union PerRequestOutputPortFlags
{
    struct
    {
        BIT isOutputHALBuffer  : 1;                     ///< Is the output of this port a HAL buffer
        BIT isBatch            : 1;                     ///< Is the batch mode enabled for this port
        BIT isDelayedBuffer    : 1;                     ///< Is delayed output buffer
        BIT isLoopback         : 1;                     ///< Is loopback port
        BIT reserved           : 28;                    ///< Reserved
    };

    UINT allFlags;
};

/// @brief Per request input port flags
union PerRequestInputPortFlags
{
    struct
    {
        BIT isInputHALBuffer    : 1;                     ///< Is the input of this port a HAL buffer
        BIT isPendingBuffer     : 1;                     ///< Is the image buffer  of this port pending to be resolved
        BIT isParentInputBuffer : 1;                     ///< Is the buffer from parent's input
        BIT reserved            : 29;                    ///< Reserved
    };

    UINT allFlags;
};

/// @brief Per request info for one output port to be sent to the derived nodes that implement request processing
struct PerRequestOutputPortInfo
{
    UINT                        portId;                             ///< PortId from XML
    ImageBuffer*                pImageBuffer[MaxBatchedFrames];     ///< All the output buffers of this port
    PerRequestOutputPortFlags   flags;                              ///< Flags
    UINT                        numOutputBuffers;                   ///< Number of output buffers that will be output
    CSLFence*                   phFence;                            ///< Fence associated with all Imagebuffers in the output
                                                                    ///  port
    UINT*                       pIsFenceSignaled;                   ///< Pointer to fence variables signaled status
    CSLFence*                   phDelayedBufferFence;               ///< Pointer to the associated fence for delayed buffer
    DelayedOutputBufferInfo*    pDelayedOutputBufferData;           ///< Pointer to the delayed output buffer
};

/// @brief Per request info for one input port to be sent to the derived nodes that implement request processing
struct PerRequestInputPortInfo
{
    UINT                     portId;                    ///< PortId from XML
    ImageBuffer*             pImageBuffer;              ///< ImageBuffer associated with the port
    PerRequestInputPortFlags flags;                     ///< Flags
    CSLFence*                phFence;                   ///< Fence associated with the ImageBuffer
    UINT*                    pIsFenceSignaled;          ///< Pointer to fence variable whose signaled status is checked
    DelayedOutputBufferInfo* pDelayedOutputBufferData;  ///< Pointer to the delayed output buffer
};

/// @brief Per request info of all enabled input/output ports to be sent to the derived nodes that implement request processing
struct PerRequestActivePorts
{
    UINT                      numOutputPorts;          ///< Number of output ports per request
    UINT                      numInputPorts;           ///< Number of input ports per request
    PerRequestOutputPortInfo* pOutputPorts;            ///< Per request output ports - points to array size numOutputPorts
    PerRequestInputPortInfo*  pInputPorts;             ///< Per request input ports  - points to array size numInputPorts
};

struct NodePerRequestInfo
{
    PerRequestActivePorts activePorts;                  ///< Per request ports info passed to derived node
    UINT                  numUnsignaledFences;          ///< Number of unsigned fences in a particular request. This is
                                                        ///  decremented with each fence that triggers for the node. 0 means
                                                        ///  all outputs are available.
    UINT64                requestId;                    ///< incoming requestId
    UINT                  metadataComplete;             ///< Binary flag representing whether metadata has been reported
    UINT                  requestComplete;              ///< Binary flag representing whether request has been reported
};

/// @brief Execute process request data to be passed to the derived nodes that implement request processing
struct ExecuteProcessRequestData
{
    NodeProcessRequestData* pNodeProcessRequestData;    ///< Request data coming in from Pipeline
    PerRequestActivePorts*  pEnabledPortsInfo;          ///< All enabled ports for the request
    ChiTuningModeParameter* pTuningModeData;            ///< Pointer to tuning mode selector data
};

/// @brief Node flags
union NodeFlags
{
    struct
    {
        BIT isEnabled                       :  1;      ///< Is the node enabled
        BIT isInplace                       :  1;      ///< Is inplace node i.e. output buffer same as input buffer
        BIT isRealTime                      :  1;      ///< Is this node part of a real time pipeline
        BIT isSecureMode                    :  1;      ///< Is this node  Secure/non-secure
        BIT isHwDeviceAcquired              :  1;      ///< Did this node successfully acquired a hw device or not
        BIT callNotifyConfigDone            :  1;      ///< Call notify config done
        BIT isBypassable                    :  1;      ///< Is this node bypassable
        BIT canDRQPreemptOnStopRecording    :  1;      ///< Can DRQ preempt node on recording stop/pause
        BIT reserved                        :  24;     ///< Reserved
    };

    UINT value;
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// @brief Class that implements the hwl node.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class Node
{
public:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Create
    ///
    /// @brief  Create node object
    ///
    /// @param  pCreateInputData  Node create input data
    /// @param  pCreateOutputData Node create output data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static CamxResult Create(
        const NodeCreateInputData* pCreateInputData,
        NodeCreateOutputData*      pCreateOutputData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyPipelineCreated
    ///
    /// @brief  Notification that the topology and all associated nodes are created
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult NotifyPipelineCreated();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DetermineBufferProperties
    ///
    /// @brief  Determine the buffer properties of each output port
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DetermineBufferProperties();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HasAnyDependency
    ///
    /// @brief  Checks if any dependencies are set
    ///
    /// @param  pDependency  Pointer to the dependency structure
    ///
    /// @return TRUE if there are any dependencies, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static CAMX_INLINE BOOL HasAnyDependency(
        const DependencyUnit* pDependency)
    {
        BOOL hasAnyDependency = FALSE;

        if ((NULL != pDependency) && (0 != pDependency->dependencyFlags.dependencyFlagsMask))
        {
            hasAnyDependency = TRUE;
        }

        return hasAnyDependency;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CreateBufferManagers
    ///
    /// @brief  Create buffer managers in all the output ports of a non-inplace node
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CreateBufferManagers();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Destroy
    ///
    /// @brief  Destroy node object
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID Destroy();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyParentHALBufferOutput
    ///
    /// @brief  This function is only called by an inplace node to inform the parent node to output a HAL buffer (to its
    ///         output port to which this inplace node is connected)
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID NotifyParentHALBufferOutput();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyHALBufferOutput
    ///
    /// @brief  This function notifies the node that its output port must output a HAL buffer. This is called by an inplace
    ///         child node that outputs a HAL buffer, to inform the parent node that it also needs to output to the same HAL
    ///         buffer
    ///
    /// @param  outputPortIndex    Output port index
    /// @param  pInplaceOutputPort Inplace child's output port info
    /// @param  pChiStreamWrapper  Output stream wrapper of inplace child
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID NotifyHALBufferOutput(
        UINT              outputPortIndex,
        OutputPort*       pInplaceOutputPort,
        ChiStreamWrapper* pChiStreamWrapper)
    {
        m_outputPortsData.pOutputPorts[outputPortIndex].flags.isNonSinkHALBufferOutput = TRUE;
        m_outputPortsData.pOutputPorts[outputPortIndex].sinkTargetStreamId = pInplaceOutputPort->sinkTargetStreamId;

        OutputPort* pOutputPort = &m_outputPortsData.pOutputPorts[outputPortIndex];
        pOutputPort->flags.isNonSinkHALBufferOutput = TRUE;

        CAMX_ASSERT(CamxInvalidStreamId != pOutputPort->sinkTargetStreamId);

        pOutputPort->enabledInStreamMask = (1 << pOutputPort->sinkTargetStreamId);
        pOutputPort->pChiStreamWrapper = pChiStreamWrapper;
        InitializeNonSinkHALBufferPortBufferProperties(outputPortIndex, pInplaceOutputPort, pChiStreamWrapper);
        TriggerBufferNegotiation();

        if (TRUE == IsInplace())
        {
            NotifyParentHALBufferOutput();
        }
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PrepareStreamOn
    ///
    /// @brief  Method that is called by topology before streamOn is sent to HW.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult PrepareStreamOn();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PrepareStreamOff
    ///
    /// @brief  Method that is called by topology before streamOff is sent to HW. Nodes may use
    ///         this hook to do preparation with respect to the bitmask passed in.
    ///
    /// @param  modeBitmask   Mode Bitmask that indicates specific tasks node needs to do during streamoff.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult PrepareStreamOff(
        CHIDEACTIVATEPIPELINEMODE modeBitmask);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetupRequest
    ///
    /// @brief  Configure a new request
    ///
    /// @param  pPerBatchedFrameInfo       Per batch information for this request
    /// @param  pDifferentActiveStreams    If the active streams is different from last request, the Pipeline will pass in
    ///                                    the new active streams for the current request. Otherwise it will be NULL.
    /// @param  requestId                  Request to (re)process
    /// @param  syncId                     Sync ID for this request
    /// @param  pIsEnabled                 Updated to report whether node ended up enabled for request
    ///
    /// @return Pointer to the per frame property/metadata pool
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult SetupRequest(
        PerBatchedFrameInfo* pPerBatchedFrameInfo,
        UINT*                pDifferentActiveStreams,
        UINT64               requestId,
        UINT64               syncId,
        BOOL*                pIsEnabled);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessRequest
    ///
    /// @brief  Method to trigger process request for a node object.
    ///
    /// @param  pNodeRequestData           Node process request data
    /// @param  requestId                  Request to process
    ///
    /// @return CamxResultSuccess if successful and 0 dependencies, dependency information otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessRequest(
        NodeProcessRequestData* pNodeRequestData,
        UINT64                  requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Type
    ///
    /// @brief  Return type of the node
    ///
    /// @return type of the node
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT Type() const
    {
        return m_nodeType;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Name
    ///
    /// @brief  Return name of the node
    ///
    /// @return name of the node
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE const CHAR* Name() const
    {
        return m_pNodeName;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NameAndInstanceId
    ///
    /// @brief  Return name and instance id of the node
    ///
    /// @return name and instance id of the node
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE const CHAR* NameAndInstanceId() const
    {
        return m_nodeNameInstanceId;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSecureMode
    ///
    /// @brief  Return Mode of the node secure/non-secure
    ///
    /// @return TRUE means SECURE mode or FALSE is non secure
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    CAMX_INLINE BOOL IsSecureMode() const
    {
        return m_nodeFlags.isSecureMode;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InstanceID
    ///
    /// @brief  Return instance id of the node
    ///
    /// @return instance id of the node
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT InstanceID() const
    {
        return m_instanceId;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DeviceIndices
    ///
    /// @brief  Return device index list of this node (the devices acquired and that access associated buffers)
    ///
    /// @return device index list pointer
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE const INT32* DeviceIndices() const
    {
        return &(m_deviceIndices[0]);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DeviceIndexCount
    ///
    /// @brief  Return device index count of this node
    ///
    /// @return device index count for this node
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT32 DeviceIndexCount() const
    {
        return m_deviceIndexCount;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddCSLDeviceHandle
    ///
    /// @brief  Add the given CSL device handle to the list for this node for linking.
    ///
    /// @param  hCslDeiveHandle to add
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult AddCSLDeviceHandle(
        CSLDeviceHandle hCslDeiveHandle);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCSLDeviceHandle
    ///
    /// @brief  Return csl handle for this node for given index.
    ///
    /// @param  index to the array of csl handle.
    ///
    /// @return device csl handle
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE CSLDeviceHandle GetCSLDeviceHandle(
        UINT32 index) const
    {
        return (index < m_cslDeviceCount) ? m_hCSLDeviceHandles[index] : 0;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CSLDeviceHandleCount
    ///
    /// @brief  Return csl device index count of this node
    ///
    /// @return device index count for this node
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT32 CSLDeviceHandleCount() const
    {
        return m_cslDeviceCount;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetOutputPortImageFormat
    ///
    /// @brief  Return output port buffer image format
    ///
    /// @param  outputPortIndex output port index into all output ports maintained in this node
    ///
    /// @return ImageFormat
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    const ImageFormat* GetOutputPortImageFormat(
        UINT outputPortIndex
        ) const
    {
        return ((outputPortIndex < m_outputPortsData.numPorts) ?
                (&m_outputPortsData.pOutputPorts[outputPortIndex].bufferProperties.imageFormat) : NULL);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetInputPortImageFormat
    ///
    /// @brief  Return input port buffer image format
    ///
    /// @param  inputPortIndex input port index into all input ports maintained in this node
    ///
    /// @return ImageFormat
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    const ImageFormat* GetInputPortImageFormat(
        UINT inputPortIndex
        ) const
    {
        const ImageFormat* pImageFormat = NULL;

        if (FALSE == IsSourceBufferInputPort(inputPortIndex))
        {
            UINT outputPortIndex = m_inputPortsData.pInputPorts[inputPortIndex].parentOutputPortIndex;

            if (inputPortIndex < m_inputPortsData.numPorts)
            {
                pImageFormat =
                    m_inputPortsData.pInputPorts[inputPortIndex].pParentNode->GetOutputPortImageFormat(outputPortIndex);
            }
        }
        else
        {
            pImageFormat = &m_inputPortsData.pInputPorts[inputPortIndex].imageFormat;
        }

        return pImageFormat;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetParentNodeType
    ///
    /// @brief  Return parent node type
    ///
    /// @param  inputPortId input port id
    ///
    /// @return parent node type
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetParentNodeType(
        UINT inputPortId
        ) const
    {

        BOOL found     = FALSE;
        UINT nodeType  = 0;
        UINT portIndex = 0;

        for (portIndex = 0; portIndex < m_inputPortsData.numPorts; portIndex++)
        {
            if (inputPortId == m_inputPortsData.pInputPorts[portIndex].portId)
            {
                found = TRUE;
                break;
            }
        }
        if ((found == TRUE) &&
            (NULL != m_inputPortsData.pInputPorts[portIndex].pParentNode))
        {
            nodeType = m_inputPortsData.pInputPorts[portIndex].pParentNode->Type();
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupCore, "cannot find portId %d", inputPortId);
        }
        return nodeType;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetOutputPortSourceType
    ///
    /// @brief  Return output port source type ID
    ///
    /// @param  outputPortIndex output port index
    ///
    /// @return port source type ID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetOutputPortSourceType(
        UINT outputPortIndex
    ) const
    {
        return m_outputPortsData.pOutputPorts[outputPortIndex].portSourceTypeId;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetInputPortSourceType
    ///
    /// @brief  Return input port source type ID
    ///
    /// @param  inputPortIndex input port index
    ///
    /// @return port source type ID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetInputPortSourceType(
        UINT inputPortIndex
    ) const
    {
        return m_inputPortsData.pInputPorts[inputPortIndex].portSourceTypeId;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OutputPortDeviceIndices
    ///
    /// @brief  Return output port device index list for a given output port
    ///
    /// @param  portIndex port index
    ///
    /// @return output port device index list pointer
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE const INT32* OutputPortDeviceIndices(
        UINT portIndex)
    {
        CAMX_ASSERT(m_outputPortsData.pOutputPorts != NULL);

        return &(m_outputPortsData.pOutputPorts[portIndex].deviceIndices[0]);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OutputPortDeviceCount
    ///
    /// @brief  Return output port device count for a given output port
    ///
    /// @param  portIndex port index
    ///
    /// @return output port device count
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT32 OutputPortDeviceCount(
        UINT portIndex)
    {
        CAMX_ASSERT(m_outputPortsData.pOutputPorts != NULL);

        return (m_outputPortsData.pOutputPorts[portIndex].deviceCount);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OutputPortCount
    ///
    /// @brief  Return number of output ports
    ///
    /// @return output port count
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT32 OutputPortCount()
    {
        return m_outputPortsData.numPorts;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OutputPortIndex
    ///
    /// @brief  Return output port index for a given port id
    ///
    /// @param  portId port id
    ///
    /// @return port index
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT OutputPortIndex(
        UINT portId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetOutputPortInfo
    ///
    /// @brief  Return output port info (mostly to be called by other nodes connected to this node)
    ///
    /// @param  requestId           requestId for which the info is seeked
    /// @param  sequenceId          sequenceId for which the info is seeked
    /// @param  outputPortIndex     output port index into the output port structure maintained in this node
    /// @param  pOutData            output data requested by the client
    ///
    /// @return CamxResultSuccess if success
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetOutputPortInfo(
        UINT64                   requestId,
        UINT32                   sequenceId,
        UINT                     outputPortIndex,
        OutputPortRequestedData* pOutData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetImageBufferManager
    ///
    /// @brief  Set image buffer manager pointer for a given output port
    ///
    /// @param  portIndex             port index
    /// @param  pImageBufferManager   image buffer manager to be set for the given port
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID SetImageBufferManager(
        UINT                portIndex,
        ImageBufferManager* pImageBufferManager)
    {
        CAMX_ASSERT(m_outputPortsData.pOutputPorts != NULL);

        m_outputPortsData.pOutputPorts[portIndex].pImageBufferManager = pImageBufferManager;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSinkPort
    ///
    /// @brief  Query for if a port is a sink port
    ///
    /// @param  portIndex queried port index
    ///
    /// @return TRUE if it is a sink port, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsSinkPort(
        UINT portIndex
        ) const
    {
        CAMX_ASSERT(portIndex < m_outputPortsData.numPorts);

        BOOL isSink = FALSE;

        if (portIndex < m_outputPortsData.numPorts)
        {
            isSink = (m_outputPortsData.pOutputPorts[portIndex].flags.isSinkBuffer ||
                      m_outputPortsData.pOutputPorts[portIndex].flags.isSinkNoBuffer);
        }

        return isSink;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSinkNoBufferNode
    ///
    /// @brief  Query for if a node is Sink node with no buffer
    ///
    /// @return TRUE if it is a sink node, with no buffer, else FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsSinkNoBufferNode() const
    {
        BOOL isSinkNoBuffer = TRUE;

        for (UINT portIndex = 0; portIndex < m_outputPortsData.numPorts; portIndex++)
        {
            isSinkNoBuffer = m_outputPortsData.pOutputPorts[portIndex].flags.isSinkNoBuffer;
            if (FALSE == isSinkNoBuffer)
            {
                break;
            }
        }

        return isSinkNoBuffer;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSourceBufferInputPort
    ///
    /// @brief  Query for if a port is a source buffer port
    ///
    /// @param  portIndex queried port index
    ///
    /// @return TRUE if it is a source buffer input port, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsSourceBufferInputPort(
        UINT portIndex
        ) const
    {
        CAMX_ASSERT(portIndex < m_inputPortsData.numPorts);

        BOOL isSource = FALSE;

        if (portIndex < m_inputPortsData.numPorts)
        {
            isSource = (m_inputPortsData.pInputPorts[portIndex].flags.isSourceBuffer);
        }

        return isSource;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsInplace
    ///
    /// @brief  Check if the node is an inplace node
    ///
    /// @return TRUE if it is a inplace node, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsInplace() const
    {
        return m_nodeFlags.isInplace;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsBypassableNode
    ///
    /// @brief  Check if the bypass property of the node is set
    ///
    /// @return TRUE if it is bypassed, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsBypassableNode() const
    {
        return m_nodeFlags.isBypassable;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsNonSinkHALBufferOutput
    ///
    /// @brief  Query for if a port is not a sink port but still outputs to a HAL buffer
    ///
    /// @param  portIndex queried port index
    ///
    /// @return TRUE if it is not a sink port but still outputs to a HAL buffer, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsNonSinkHALBufferOutput(
        UINT portIndex
        ) const
    {
        CAMX_ASSERT((portIndex < m_outputPortsData.numPorts) && (FALSE == IsSinkPort(portIndex)));

        return ((portIndex < m_outputPortsData.numPorts) ?
                m_outputPortsData.pOutputPorts[portIndex].flags.isNonSinkHALBufferOutput : FALSE);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSinkPortWithBuffer
    ///
    /// @brief  Query for if a port is a sink port with output buffer
    ///
    /// @param  portIndex queried port index
    ///
    /// @return TRUE if it is a sink port with output buffer, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsSinkPortWithBuffer(
        UINT portIndex
        ) const
    {
        CAMX_ASSERT(portIndex < m_outputPortsData.numPorts);

        BOOL isSink = FALSE;

        if (portIndex < m_outputPortsData.numPorts)
        {
            isSink = m_outputPortsData.pOutputPorts[portIndex].flags.isSinkBuffer;
        }

        return isSink;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsSinkPortNoBuffer
    ///
    /// @brief  Query for if a port is a sink port with no output buffer
    ///
    /// @param  portIndex queried port index
    ///
    /// @return TRUE if it is a sink port with no output buffer, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsSinkPortNoBuffer(
        UINT portIndex
        ) const
    {
        CAMX_ASSERT(portIndex < m_outputPortsData.numPorts);

        BOOL isSinkPortNoBuffer = FALSE;

        if (portIndex < m_outputPortsData.numPorts)
        {
            isSinkPortNoBuffer = m_outputPortsData.pOutputPorts[portIndex].flags.isSinkNoBuffer;
        }

        return isSinkPortNoBuffer;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsBatchEnabledPort
    ///
    /// @brief  Query for if a port has batch mode enabled
    ///
    /// @param  portIndex queried port index
    ///
    /// @return TRUE if the port has batch mode enabled
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsBatchEnabledPort(
        UINT portIndex
    ) const
    {
        CAMX_ASSERT(portIndex < m_outputPortsData.numPorts);

        BOOL isBatchEnabledPort = FALSE;

        if (portIndex < m_outputPortsData.numPorts)
        {
            isBatchEnabledPort = m_outputPortsData.pOutputPorts[portIndex].flags.isBatchMode;
        }

        return isBatchEnabledPort;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsOutputPortSecure
    ///
    /// @brief  Query for if a port is secure or Non-secure
    ///
    /// @param  portId queried port Id
    ///
    /// @return TRUE if the port is secure, else FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsOutputPortSecure(
        UINT portId)
    {
        UINT index = OutputPortIndex(portId);

        CAMX_ASSERT(index < m_outputPortsData.numPorts);

        BOOL isSecurePort = FALSE;

        if (index < m_outputPortsData.numPorts)
        {
            isSecurePort = m_outputPortsData.pOutputPorts[index].flags.isSecurePort;
        }
        else
        {
            CAMX_LOG_ERROR(CamxLogGroupCore, "Invalid parameters.  nodeType = %d, portIndex = %d, numPorts = %d",
                m_nodeType, portId, m_outputPortsData.numPorts);
        }

        return isSecurePort;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsTorchWidgetNode
    ///
    /// @brief  Query whether this is Torch Widget node
    ///
    /// @return TRUE if node is Torch widget node.
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsTorchWidgetNode()
    {
        return (Torch == Type());
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetInputLink
    ///
    /// @brief  Fill input link information
    ///
    /// @param  nodeInputLinkIndex  Input link index to be set
    /// @param  nodeInputPortId     Port name/id (coming from topology XML)
    /// @param  pParentNode         Parent node pointer for input link
    /// @param  parentPortId        Parent port id for the input link
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetInputLink(
        UINT  nodeInputLinkIndex,
        UINT  nodeInputPortId,
        Node* pParentNode,
        UINT  parentPortId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetupSourcePort
    ///
    /// @brief  Fill input source port information
    ///
    /// @param  nodeInputPortIndex  Input link index to be set
    /// @param  nodeInputPortId     Port name/id (coming from topology XML)
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetupSourcePort(
        UINT  nodeInputPortIndex,
        UINT  nodeInputPortId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetUpLoopBackPorts
    ///
    /// @brief  Fill input link information
    ///
    /// @param  inputPortIndex  Input link index to be set
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetUpLoopBackPorts(
        UINT  inputPortIndex);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NodeThreadJobFamilyCb
    ///
    /// @brief  Static Node worker function that will be called by the threadpool for jobs registered by the node
    ///
    /// @param  pCbData Thread payload, which is the node private data (including the node object)
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static VOID* NodeThreadJobFamilyCb(
        VOID* pCbData);


    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyInputConsumed
    ///
    /// @brief  Notification that the input port buffer has been consumed by some other node (who used it as input)
    ///         , applicable for bypassable custom node
    ///
    /// @param  inputPortIndex  Input port whose buffer has been consumed
    /// @param  requestId       RequestId for which the output port data is consumed
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID NotifyInputConsumed(
        UINT   inputPortIndex,
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyOutputConsumed
    ///
    /// @brief  Notification that the output port buffer has been consumed by some other node (who used it as input)
    ///
    /// @param  outputPortIndex Output port whose buffer has been consumed
    /// @param  requestId       RequestId for which the output port data is consumed
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID NotifyOutputConsumed(
        UINT   outputPortIndex,
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// BufferRequirementNotification
    ///
    /// @brief  Once a node determines the buffer requirement of its input ports, it calls this function of the parent node
    ///         (connected to its input ports) to inform the parent node of the its output buffer requirement
    ///
    /// @param  outputPortIndex    Pointer to array of device indices that would be added to access list for the output port
    /// @param  pBufferRequirement The number of valid entries in the device index array
    ///
    /// @return Success or Failure
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult BufferRequirementNotification(
        UINT               outputPortIndex,
        BufferRequirement* pBufferRequirement);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddOutputDeviceIndices
    ///
    /// @brief  Update output port device index list by adding the device index list passed
    ///
    /// @param  portId           Output port id
    /// @param  pDeviceIndices   Pointer to array of device indices that would be added to the access list for the output port
    /// @param  deviceIndexCount The number of valid entries in the device index array
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID AddOutputDeviceIndices(
        UINT         portId,
        const INT32* pDeviceIndices,
        UINT         deviceIndexCount);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TriggerOutputPortStreamIdSetup
    ///
    /// @brief  This function is called only for nodes with one or more sink ports. It is called by topology after all nodes
    ///         for a usecase are created. Function triggers a graph-walk-back starting with this node and going all the way
    ///         back to the head node of the graph. As it traverses back to the head node all the nodes visited in between
    ///         will be updated with the information of which output ports in them need to be enabled if this node's sink port
    ///         is active. For a particular capture request if this node's sink port is not active, other nodes will disable
    ///         their output ports that need to be enabled only if this node's sink port is active.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID TriggerOutputPortStreamIdSetup();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// EnableParentOutputPorts
    ///
    /// @brief  This function is called only if the node has loop back ports, and thus require its parent node output ports
    ///         to be always enabled by setting the stream mask.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID EnableParentOutputPorts();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TriggerBufferNegotiation
    ///
    /// @brief  This function is invoked for nodes with sink ports to trigger the buffer negotiation process. If this function
    ///         returns failure, configure_streams will return failure
    ///
    /// @return Success if buffer negotiation succeeded, Failure otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult TriggerBufferNegotiation();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// TriggerInplaceProcessing
    ///
    /// @brief  This function is invoked for inplace nodes with SinkBuffer ports to inform its parent (and potentially its
    ///         parent) to output the HAL buffer
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID TriggerInplaceProcessing();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetOutputPortEnabledForStreams
    ///
    /// @brief  Set streamId (which if active) would enable this output port. The stream(Id) itself may or may not be enabled
    ///         per request. So based on whether the streamId is enabled in a request or not, will decide whether this output
    ///         port is enabled for that request or not.
    ///
    /// @param  outputPortIndex  Output port index (in the output ports array)
    /// @param  streamIdMask     StreamIds which if active for a request will enable the output port for that request
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetOutputPortEnabledForStreams(
        UINT outputPortIndex,
        UINT streamIdMask);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetJobFamilyHandle
    ///
    /// @brief  Get the job family handle to post jobs to the job family
    ///
    /// @return JobHandle
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE JobHandle GetJobFamilyHandle() const
    {
        return m_hThreadJobFamilyHandle;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FinalizeInitialization
    ///
    /// @brief  Method to finalize the initialization of the node in the pipeline
    ///
    /// @param  pFinalizeInitializationData Finalize data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult FinalizeInitialization(
        FinalizeInitializationData* pFinalizeInitializationData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SwitchNodeOutputFormat
    ///
    /// @brief  Method to finalize the initialization of the node in the pipeline
    ///
    /// @param  format Format
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult SwitchNodeOutputFormat(
        Format format);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ResetBufferNegotiationData
    ///
    /// @brief  Reset buffer negotiation data
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ResetBufferNegotiationData();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FillPipelineInputOptions
    ///
    /// @brief  Get the buffer requirements on the source input ports
    ///
    /// @param  pInputOptions   Buffer options on the input ports
    ///
    /// @return number of inputs filled
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT FillPipelineInputOptions(
        ChiPipelineInputOptions* pInputOptions);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// EarlyReturnTag
    ///
    /// @brief  Determins if the tag is one of the speical early return tags
    ///
    /// @param  requestId   requestId
    /// @param  tag         Tag to check
    /// @param  pData       data to write
    /// @param  size        size
    ///
    /// @return TRUE if it is an early return tag
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL EarlyReturnTag(
        UINT64       requestId,
        UINT32       tag,
        const VOID*  pData,
        SIZE_T       size);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetDataCountFromPipeline
    ///
    /// @brief  Fetches tag count data pools for the provided data id
    ///
    /// @param  id          Tag to fetch count for
    /// @param  offset      Offset from the current request to read
    /// @param  pipelineID  The pipeline ID indicating the pipeline that owns the pool
    /// @param  allowSticky For input pool, allow use of sticky tag data, or force use of count in request metadata
    ///
    /// @return Count of tag
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    SIZE_T GetDataCountFromPipeline(
        const UINT   id,
        INT64        offset,
        UINT         pipelineID,
        BOOL         allowSticky);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetDataListFromPipeline
    ///
    /// @brief  Fetches data pointers from data pools for the provided data ids
    ///
    /// @param  pDataList   Array of data identifiers to be updated
    /// @param  ppData      Array of data to update in the pool
    /// @param  pOffsets    Array of offsets from the current requestID to determine slot from which data pointer is obtained
    /// @param  length      Length of all the arrays
    /// @param  pNegate     Array of negate flags to indicate if the value of offsets are negative
    /// @param  pipelineID  The pipeline ID indicating the pipeline that owns the pool
    ///
    /// @return Result of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetDataListFromPipeline(
        const UINT*  pDataList,
        VOID** const ppData,
        UINT64*      pOffsets,
        SIZE_T       length,
        BOOL*        pNegate,
        UINT         pipelineID);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetDataList
    ///
    /// @brief  Fetches data pointers from data pools for the provided data ids
    ///
    /// @param  pDataList Array of data identifiers to be updated
    /// @param  ppData    Array of data to update in the pool
    /// @param  pOffsets  Array of offsets from the current requestID to determine slot from which data pointer is obtained
    /// @param  length    Length of all the arrays
    ///
    /// @return Result of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetDataList(
        const UINT*  pDataList,
        VOID** const ppData,
        UINT64*      pOffsets,
        SIZE_T       length);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetSensorModeData
    ///
    /// @brief  Fetches sensor mode
    ///
    /// @param  ppSensorData Pointer to fill with lookup
    ///
    /// @return Result of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetSensorModeData(
        const SensorMode** ppSensorData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetSensorModeRes0Data
    ///
    /// @brief  Fetches sensor mode
    ///
    /// @param  ppSensorData Pointer to fill with lookup
    ///
    /// @return Result of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetSensorModeRes0Data(
        const SensorMode** ppSensorData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCameraConfiguration
    ///
    /// @brief  Fetches Camera Configuration
    ///
    /// @param  ppCameraConfigInfo Pointer to fill with lookup
    ///
    /// @return Result of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetCameraConfiguration(
        const CameraConfigurationInformation** ppCameraConfigInfo);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetIFEInputResolution
    ///
    /// @brief  Fetches IFE input Resoulution
    ///
    /// @param  ppIFEInput Pointer to fill with lookup
    ///
    /// @return Result of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetIFEInputResolution(
        const IFEInputResolution** ppIFEInput);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPreviewDimension
    ///
    /// @brief  Retrieve the preview dimension
    ///
    /// @param  pPreviewDimension  Output pointer to preview dimension
    ///
    /// @return return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetPreviewDimension(
        CamxDimension* pPreviewDimension);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WritePreviousData
    ///
    /// @brief  Copies tag/prop from request - 1 to request
    ///
    /// @param  dataId    Tag/Prop to update
    /// @param  size      size of tag data to copy
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID WritePreviousData(
        UINT32 dataId,
        UINT   size);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WriteDataList
    ///
    /// @brief  Updates data in the data pools
    ///
    /// @param  pDataList Array of data identifiers to be updated
    /// @param  ppData    Array of data to update in the pool
    /// @param  pDataSize Array of sizes of the data in pData
    /// @param  length    Length of all the arrays
    ///
    /// @return Result of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult WriteDataList(
        const UINT*  pDataList,
        const VOID** ppData,
        const UINT*  pDataSize,
        SIZE_T       length);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyNodeCSLMessage
    ///
    /// @brief  Base Method to notify CSL message to nodes
    ///
    /// @param  pCSLMessage CSL message data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult NotifyNodeCSLMessage(
        CSLMessage* pCSLMessage)
    {
        m_tRequestId = pCSLMessage->message.frameMessage.requestID;

        return NotifyCSLMessage(pCSLMessage);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyCSLMessage
    ///
    /// @brief  Method to notify CSL message to nodes
    ///
    /// @param  pCSLMessage CSL message data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult NotifyCSLMessage(
        CSLMessage* pCSLMessage)
    {
        CAMX_UNREFERENCED_PARAM(pCSLMessage);

        return CamxResultSuccess;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPerFramePool
    ///
    /// @brief  Gets the pointer to the per frame property/metadata pool
    ///
    /// @param  poolType Type of the per-frame pool asked for
    ///
    /// @return Pointer to the per frame property/metadata pool
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    MetadataPool* GetPerFramePool(
        PoolType poolType);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCurrentRequest
    ///
    /// @brief  Gets the id of the request being processed
    ///
    /// @note   Should only call this within the ProcessRequest call stack (including ExecuteProcessRequest)
    ///
    /// @return Value of current request
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT64 GetCurrentRequest() const
    {
        return m_tRequestId;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPipelineId
    ///
    /// @brief  Gets the id of node's owning pipeline
    ///
    /// @return id of pipeline
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT GetPipelineId()
    {
        return m_pPipeline->GetPipelineId();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetStaticSettings
    ///
    /// @brief  Helper method to return the settings pointer.
    ///
    /// @return HwContext*
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    const StaticSettings* GetStaticSettings() const;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsPipelineStreamedOn
    ///
    /// @brief  Utility to check if the pipeline has been streamed on
    ///
    /// @return TRUE/FALSE based on stream on state
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsPipelineStreamedOn();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// BypassNodeProcessing
    ///
    /// @brief  Process Bypass node
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID BypassNodeProcessing();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsLoopBackNode
    ///
    /// @brief  Check if node has loop back ports
    ///
    /// @return TRUE/FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsLoopBackNode()
    {
        return m_bHasLoopBackPorts;
    };

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpState
    ///
    /// @brief  Dumps snapshot of current state to a file
    ///
    /// @param  fd          file descriptor
    /// @param  indent      indent spaces.
    /// @param  requestId   requestId.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DumpState(
        INT     fd,
        UINT32  indent,
        UINT64  requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpNodeInfo
    ///
    /// @brief  Dumps static Node info
    ///
    /// @param  fd      file descriptor
    /// @param  indent  indent spaces.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DumpNodeInfo(
        INT     fd,
        UINT32  indent);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpLinkInfo
    ///
    /// @brief  Dumps static Node link info
    ///
    /// @param  fd      file descriptor
    /// @param  indent  indent spaces.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DumpLinkInfo(
        INT     fd,
        UINT32  indent);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CanDRQPreemptOnStopRecording
    ///
    /// @brief  Check if DRQ can preempt EPR for this node on stop recording
    ///
    /// @return TRUE if enabled, FALSE if disabled
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL CanDRQPreemptOnStopRecording() const
    {
        return m_nodeFlags.canDRQPreemptOnStopRecording;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetCSLSyncId
    ///
    /// @brief  Function to return CSL sync ID per request
    ///
    /// @param  requestId requestId to match csl sync id
    /// @param  syncId    CSL sync id.
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID SetCSLSyncId(
        UINT64 requestId,
        UINT64 syncId)
    {
        CamxAtomicStoreU64(&m_CSLSyncID[requestId%MaxRequestBufferDepth], syncId);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCSLSyncId
    ///
    /// @brief  Function to return CSL sync ID per request
    ///
    /// @param  requestId requestId to match csl sync id
    ///
    /// @return syncID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT64 GetCSLSyncId(
        UINT64 requestId)
    {
        UINT64 syncid = CamxAtomicLoadU64(&m_CSLSyncID[requestId%MaxRequestBufferDepth]);

        if (CamxInvalidRequestId == syncid)
        {
            syncid = requestId;
        }

        return syncid;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNodeCompleteProperty
    ///
    /// @brief  Utility to compute property updated at the end of request processing
    ///
    /// @return PropertyID
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetNodeCompleteProperty()
    {
        CAMX_ASSERT(NodeCompleteCount > m_pipelineNodeIndex);

        return PropertyIDNodeComplete0 + m_pipelineNodeIndex;
    }

protected:

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// HasParentNode
    ///
    /// @brief  Return parent if node has a parent
    ///
    /// @param  inputPortId input port id
    ///
    /// @return BOOL
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT HasParentNode(
        UINT inputPortId
    ) const
    {
        BOOL hasParent = FALSE;
        UINT portIndex = 0;

        for (portIndex = 0; portIndex < m_inputPortsData.numPorts; portIndex++)
        {
            if ((inputPortId == m_inputPortsData.pInputPorts[portIndex].portId) &&
                (NULL != m_inputPortsData.pInputPorts[portIndex].pParentNode))
            {
                hasParent = TRUE;
                break;
            }
        }
        return hasParent;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetTuningDataManager
    ///
    /// @brief  Gets the pointer to the pipeline
    ///
    /// @return Pointer to the thread pool manager
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    TuningDataManager* GetTuningDataManager();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetTuningDataManagerWithCameraId
    ///
    /// @brief  Gets the pointer to the pipeline
    ///
    /// @param  cameraId  camera id
    ///
    /// @return Pointer to the thread pool manager
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    TuningDataManager* GetTuningDataManagerWithCameraId(
    UINT32 cameraId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsRealTime
    ///
    /// @brief  Method to query if node is part of realtime pipeline
    ///
    /// @return TRUE or FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsRealTime() const
    {
        return m_nodeFlags.isRealTime;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsDeviceAcquired
    ///
    /// @brief  Check if any hw device is acquired
    ///
    /// @return TRUE if hw device is successfully acquired, FALSE otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsDeviceAcquired() const
    {
        return m_nodeFlags.isHwDeviceAcquired;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetDeviceAcquired
    ///
    /// @brief  Set hw device acquire state
    ///
    /// @param  isAcquired acquire state to be set
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID SetDeviceAcquired(
        BOOL isAcquired)
    {
        m_nodeFlags.isHwDeviceAcquired = (TRUE == isAcquired) ? 1 : 0;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessingNodeFinalizeInitialization
    ///
    /// @brief  Method to finalize the initialization of the node in the pipeline
    ///
    /// @param  pFinalizeInitializationData Finalize data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult ProcessingNodeFinalizeInitialization(
        FinalizeInitializationData* pFinalizeInitializationData)
    {
        CAMX_UNREFERENCED_PARAM(pFinalizeInitializationData);

        return CamxResultSuccess;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetHwContext
    ///
    /// @brief  Helper method to return the HW context.
    ///
    /// @return HwContext*
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE HwContext* GetHwContext() const
    {
        return m_pHwContext;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetChiContext
    ///
    /// @brief  Helper method to return the Chi context.
    ///
    /// @return ChiContext*
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE ChiContext* GetChiContext() const
    {
        return m_pChiContext;;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessingNodeInitialize
    ///
    /// @brief  Initialize the hwl or sw object
    ///
    /// @param  pCreateInputData  Node create input data
    /// @param  pCreateOutputData Node create output data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult ProcessingNodeInitialize(
        const NodeCreateInputData* pCreateInputData,
        NodeCreateOutputData*      pCreateOutputData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessingNodeFinalizeInputRequirement
    ///
    /// @brief  Implemented by derived nodes to determine its input buffer requirement based on all the output buffer
    ///         requirements
    ///
    /// @param  pBufferNegotiationData  Negotiation data for all output ports of a node
    ///
    /// @return Success if the negotiation was successful, Failure otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult ProcessingNodeFinalizeInputRequirement(
        BufferNegotiationData* pBufferNegotiationData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FinalizeBufferProperties
    ///
    /// @brief  Finalize the buffer properties of each output port
    ///
    /// @param  pBufferNegotiationData Buffer negotiation data
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual VOID FinalizeBufferProperties(
        BufferNegotiationData* pBufferNegotiationData)
    {
        // A node may not necessarily need to do any work here if:
        //
        // 1. A node with sink no buffer ports only
        // 2. A node with all output ports as sink buffers

        CAMX_UNREFERENCED_PARAM(pBufferNegotiationData);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessInputBufferRequirement
    ///
    /// @brief  This function is called after all the buffer negotiation data is available for the node. It will call the
    ///         derived node to compute the final input buffer requirement and output port buffer dimensions. It then informs
    ///         the parent nodes of the input buffer requirements
    ///
    /// @return Success or Failure
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessInputBufferRequirement();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// PostPipelineCreate
    ///
    /// @brief  virtual method to be called at NotifyPipelineCreated time; node should take care of updates and initialize
    ///         blocks that has dependency on other nodes in the topology at this time.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult PostPipelineCreate();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetAllOutputPortIds
    ///
    /// @brief  Get all the output port Ids of the node which are active
    ///
    /// @param  pNumPorts Number of output ports to be filled in by this function
    /// @param  pPortIds  Array of port Ids filled in by this function (array allocated by caller)
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID GetAllOutputPortIds(
        UINT* pNumPorts,
        UINT* pPortIds);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ResetSecureMode
    ///
    /// @brief  Resets Secure mode of port
    ///
    /// @param  portId  PortId
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ResetSecureMode(
        UINT32 portId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetAllInputPortIds
    ///
    /// @brief  Get all the input port Ids of the node
    ///
    /// @param  pNumPorts Number of input ports to be filled in by this function
    /// @param  pPortIds  Array of port Ids filled in by this function (array allocated by caller)
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID GetAllInputPortIds(
        UINT* pNumPorts,
        UINT* pPortIds);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OnStreamOn
    ///
    /// @brief  virtual method to that will be called before streamOn command is sent to HW. HW nodes may use
    ///         this hook to do any preparation, or per-configure_stream one-time configuration.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult OnStreamOn();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// OnStreamOff
    ///
    /// @brief  virtual method to that will be called before streamOff command is sent to HW. HW nodes may use
    ///         this hook to do any preparation.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult OnStreamOff();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsNodeDisabledWithOverride
    ///
    /// @brief  virtual method that will be called during NewActiveStreamsSetup. Nodes may use
    ///         this hook to disable processing if theyre disabled through settings.
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual BOOL IsNodeDisabledWithOverride();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ExecuteProcessRequest
    ///
    /// @brief  Pure virtual method to trigger process request for the hwl node object.
    ///
    /// @param  pExecuteProcessRequestData Process request data
    ///
    /// @return CamxResultSuccess if successful and 0 dependencies, dependency information otherwise
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual CamxResult ExecuteProcessRequest(
        ExecuteProcessRequestData* pExecuteProcessRequestData) = 0;

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeCmdBufferManagerList
    ///
    /// @brief  Helper method to allow HW subnodes to initialize command manager store based on their requirements.
    ///
    /// @param  maxNumManagers  Max number of managers that may be requested throughout the nodes' lifetime
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult InitializeCmdBufferManagerList(
        UINT maxNumManagers);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CreateCmdBufferManager
    ///
    /// @brief  A helper function to allow sub-classes to create and add command buffer managers that parent node will manage.
    ///
    /// @param  pParams             Parameters the manager was created with.
    /// @param  ppCmdBufferManager  Pointer to the manager
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult CreateCmdBufferManager(
        const ResourceParams* pParams,
        CmdBufferManager**    ppCmdBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCmdBufferForRequest
    ///
    /// @brief  Helper method to acquire a free command buffer from the given manager.
    ///
    /// @param  requestId           The request Id to which this resource's lifecycle will be tied to
    /// @param  pCmdBufferManager   Command buffer manager from which a buffer is acquired
    ///
    /// @return Pointer to a CmdBuffer object
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CmdBuffer* GetCmdBufferForRequest(
        UINT64              requestId,
        CmdBufferManager*   pCmdBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CheckCmdBufferWithRequest
    ///
    /// @brief  Helper method to checkout a used command buffer from the given manager.
    ///
    /// @param  requestId           The request Id to which this resource's lifecycle will be tied to
    /// @param  pCmdBufferManager   Command buffer manager from which a buffer is acquired
    ///
    /// @return Pointer to a CmdBuffer object
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CmdBuffer* CheckCmdBufferWithRequest(
            UINT64              requestId,
            CmdBufferManager*   pCmdBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPacketForRequest
    ///
    /// @brief  Helper method to acquire a free packet from the given manager.
    ///
    /// @param  requestId           The request Id to which this resource's lifecycle will be tied to
    /// @param  pCmdBufferManager   Command buffer manager from which a buffer is acquired
    ///
    /// @return Pointer to a Packet object
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    Packet* GetPacketForRequest(
        UINT64              requestId,
        CmdBufferManager*   pCmdBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetCmdBuffer
    ///
    /// @brief  Helper method to acquire a free command buffer from the given manager.
    ///
    /// @param  pCmdBufferManager   Command buffer manager from which a buffer is acquired
    ///
    /// @return Pointer to a CmdBuffer object
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CmdBuffer* GetCmdBuffer(
        CmdBufferManager* pCmdBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPacket
    ///
    /// @brief  Helper method to acquire a free packet from the given manager.
    ///
    /// @param  pCmdBufferManager   Command buffer manager from which a buffer is acquired
    ///
    /// @return Pointer to a Packet object
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    Packet* GetPacket(
        CmdBufferManager* pCmdBufferManager);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddDeviceIndex
    ///
    /// @brief  Add the given device index to the list of indices for this node
    ///
    /// @param  deviceIndex Device index to add
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult AddDeviceIndex(
        INT32 deviceIndex);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Node
    ///
    /// @brief  Constructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    Node();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ~Node
    ///
    /// @brief  Destructor
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual ~Node();

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetIntraPipelinePerFramePool
    ///
    /// @brief  Gets the pointer to the per frame property/metadata pool of Intra pipeline
    ///
    /// @param  poolType          Type of the per-frame pool asked for
    /// @param  intraPipelineId   Intra pipeline id of the frame property tool want to get
    ///
    /// @return Pointer to the per frame property/metadata pool
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    MetadataPool* GetIntraPipelinePerFramePool(
        PoolType poolType,
        UINT     intraPipelineId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetPipeline
    ///
    /// @brief  Gets the pointer to the pipeline
    ///
    /// @return Pointer to the thread pool manager
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE Pipeline* GetPipeline()
    {
        return m_pPipeline;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsNodeInPipeline
    ///
    /// @brief  Check if the node in the pipeline
    ///
    /// @param  nodeType   node type
    ///
    /// @return TRUE if find the node, otherwise FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsNodeInPipeline(
        UINT nodeType)
    {
        return m_pPipeline->IsNodeExist(nodeType);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsPipelineHasSnapshotJPEGStream
    ///
    /// @brief  Check if the pipeline has snapshot JPEG stream
    ///
    /// @return TRUE if the pipeline has snapshot JPEG stream, otherwise FALSE
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    BOOL IsPipelineHasSnapshotJPEGStream()
    {
        return m_pPipeline->HasSnapshotJPEGStream();
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetThreadManager
    ///
    /// @brief  Gets the pointer to the thread pool manager
    ///
    /// @return Pointer to the thread pool manager
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE ThreadManager* GetThreadManager()
    {
        return m_pThreadManager;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessRequestIdDone
    ///
    /// @brief  Method to indicate that the requestId has been completely handled (all output data generated)
    ///
    /// @param  requestId requestId for which all outputs are generated
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ProcessRequestIdDone(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessMetadataDone
    ///
    /// @brief  Method to indicate that the metadata for this requestId has been completely handled
    ///
    /// @param  requestId requestId for which metadata is generated
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ProcessMetadataDone(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessEarlyMetadataDone
    ///
    /// @brief  Method to indicate that the metadata for this requestId has been completely handled
    ///
    /// @param  requestId requestId for which metadata is generated
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ProcessEarlyMetadataDone(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetOutputPortId
    ///
    /// @brief  Get the output port Id
    ///
    /// @param  outputPortIndex Output port index
    ///
    /// @return Port id
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT GetOutputPortId(
        UINT outputPortIndex
        ) const
    {
        CAMX_ASSERT(outputPortIndex < m_outputPortsData.numPorts);

        OutputPort* pOutputPort = &m_outputPortsData.pOutputPorts[outputPortIndex];

        return pOutputPort->portId;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNumOutputPorts
    ///
    /// @brief  Get the number of output ports
    ///
    /// @return Number of output ports
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT GetNumOutputPorts() const
    {
        return m_outputPortsData.numPorts;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetOutputPortNumBatchFrames
    ///
    /// @brief  Get the output port number of batch frames
    ///
    /// @param  outputPortIndex Output port index
    ///
    /// @return number of batch frames
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE UINT GetOutputPortNumBatchFrames(
        UINT outputPortIndex
    ) const
    {
        CAMX_ASSERT(outputPortIndex < m_outputPortsData.numPorts);

        OutputPort* pOutputPort = &m_outputPortsData.pOutputPorts[outputPortIndex];

        return pOutputPort->numBatchedFrames;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetInputPortBufferDelta
    ///
    /// @brief  Sets the input ports buffer delta value. The delata indicates which previous buffer is needed for the request.
    ///
    /// @param  portIndex        Input Port Index
    /// @param  delta            The delta value to set
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID SetInputPortBufferDelta(
        UINT    portIndex,
        UINT64  delta);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DisableInputOutputLink
    ///
    /// @brief  Disable one input link from the output port
    ///
    /// @param  nodeInputIndex  Input port index which is to be disabled
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DisableInputOutputLink(
        UINT nodeInputIndex);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RemoveOutputDeviceIndices
    ///
    /// @brief  Remove the list of devices from output port
    ///
    /// @param  portIndex        Output Port index to remove devices from
    /// @param  pDeviceIndices   List of devcie indices to be removed
    /// @param  deviceIndexCount Count of devices indices in pDeviceIndices
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID RemoveOutputDeviceIndices(
        UINT         portIndex,
        const INT32* pDeviceIndices,
        UINT         deviceIndexCount);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetMultiCameraInfo
    ///
    /// @brief  Get Multi camera information
    ///
    /// @param  pIsMultiCameraUsecase   Whether current use case is multi camera use case
    /// @param  pNumberOfCamerasRunning Number of cameras currently running
    /// @param  pIsMasterCamera         Whether this is master camera (or aux camera)
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult GetMultiCameraInfo(
        BOOL*   pIsMultiCameraUsecase,
        UINT32* pNumberOfCamerasRunning,
        BOOL*   pIsMasterCamera);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ReleaseImageBuffers
    ///
    /// @brief  Release all the image buffers allocated through cslalloc of every port in this node
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ReleaseImageBuffers();

    BOOL        m_derivedNodeHandlesMetaDone; ///< Derived nodes take responsiblity of calling ProcessMetadataDone
    const CHAR* m_pNodeName;                  ///< String representing node type
    UINT32      m_maxPipelineDelay;           ///< Convenience variable for getting the setting with same name
    UINT32      m_pipelineDelayOffset;        ///< Max offset used by node
    BOOL        m_parallelProcessRequests;    ///< Are ExecuteProcessRequest calls allowed to be threaded
    UINT        m_maxjpegsize;                ///< Max jpeg image buffer size

private:
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// Initialize
    ///
    /// @brief  Method to initialize Node object.
    ///
    /// @param  pCreateInputData  Node create input data
    /// @param  pCreateOutputData Node create output data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult Initialize(
        const NodeCreateInputData* pCreateInputData,
        NodeCreateOutputData*      pCreateOutputData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeNonSinkPortBufferProperties
    ///
    /// @brief  Method to initialize buffer properties of a non sink port buffer
    ///
    /// @param  outputPortIndex     Output port index
    /// @param  pPortLink           Port link information
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID InitializeNonSinkPortBufferProperties(
        UINT            outputPortIndex,
        const PortLink* pPortLink);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeSinkPortBufferProperties
    ///
    /// @brief  Method to initialize buffer properties of the sink port buffer
    ///
    /// @param  outputPortIndex      Output port index
    /// @param  pNodeCreateInputData Node create input data
    /// @param  pOutputPortInfo      Output port info
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID InitializeSinkPortBufferProperties(
        UINT                        outputPortIndex,
        const NodeCreateInputData*  pNodeCreateInputData,
        const OutputPortInfo*       pOutputPortInfo);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeSourcePortBufferFormat
    ///
    /// @brief  Method to initialize buffer format of the source port buffer
    ///
    /// @param  inPortIndex         Input port index
    /// @param  pChiStreamWrapper   Stream wrapper class
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID InitializeSourcePortBufferFormat(
        UINT              inPortIndex,
        ChiStreamWrapper* pChiStreamWrapper);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// InitializeNonSinkHALBufferPortBufferProperties
    ///
    /// @brief  Method to initialize buffer properties of the Non sink HAL buffer port
    ///
    /// @param  outputPortIndex     Output port index
    /// @param  pInplaceOutputPort  Output port info
    /// @param  pChiStreamWrapper   Stream info
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID InitializeNonSinkHALBufferPortBufferProperties(
        UINT                    outputPortIndex,
        const OutputPort*       pInplaceOutputPort,
        const ChiStreamWrapper* pChiStreamWrapper);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CSLFenceCallback
    ///
    /// @brief  CSL calls this function to inform about a signaled fence
    ///
    /// @param  pNodePrivateFenceData Private data for the callback. This data is passed by the client to CSL when the client
    ///                               registers the callback and CSL simply passes it back to the client
    /// @param  hSyncFence            Fence for which the fence is signaled
    /// @param  fenceResult           Indicates errors if any
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static VOID CSLFenceCallback(
        VOID*           pNodePrivateFenceData,
        CSLFence        hSyncFence,
        CSLFenceResult  fenceResult);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessFenceCallback
    ///
    /// @brief  Function that does any processing required for a fence callback. When CSL notifies the Node of a fence we
    ///         post a job in the threadpool. And when threadpool calls us to process the fence-signal notification, this
    ///         function does the necessary processing.
    ///
    /// @param  pFenceHandlerData Pointer to struct FenceHandlerData that belongs to this node
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID ProcessFenceCallback(
        NodeFenceHandlerData* pFenceHandlerData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessingNodeFenceCallback
    ///
    /// @brief  Fence notify mechanism to the derived nodes in case they need to know when a output ports buffer is available
    ///
    /// @param  requestId   Request Id whose fence has come back
    /// @param  portId      Port Id whose fence has come back
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual VOID ProcessingNodeFenceCallback(
        UINT64 requestId,
        UINT   portId)
    {
        CAMX_UNREFERENCED_PARAM(requestId);
        CAMX_UNREFERENCED_PARAM(portId);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NotifyRequestProcessingError
    ///
    /// @brief  Function that does any processing required for a error fence callback. When CSL notifies the Node of a fence we
    ///         post a job in the threadpool. And when threadpool calls us to process the fence-signal notification, this
    ///         function does the necessary error processing.
    ///
    /// @param  pFenceHandlerData Pointer to struct FenceHandlerData that belongs to this node
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    virtual VOID NotifyRequestProcessingError(
            NodeFenceHandlerData* pFenceHandlerData)
    {
        CAMX_ASSERT(NULL != pFenceHandlerData);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// ProcessNonSinkPortNewRequest
    ///
    /// @brief  Any output port processing required for a new request (should be called *ONLY* for ports that do not output HAL
    ///         buffer
    ///
    /// @param  requestId           RequestId for which to perform any processing
    /// @param  sequenceId          sequenceId for which the info is seeked
    /// @param  pOutputPort         Pointer to the output port
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult ProcessNonSinkPortNewRequest(
        UINT64      requestId,
        UINT32      sequenceId,
        OutputPort* pOutputPort);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// NewActiveStreamsSetup
    ///
    /// @brief  When Pipeline receives a different set of enabled streams for a request as compared to the previous request,
    ///         it informs the node about it in. This function does the processing relating to the streams changing from
    ///         one request to another.
    ///
    /// @param  activeStreamIdMask  Active stream mask
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID NewActiveStreamsSetup(
        UINT activeStreamIdMask);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// CreateImageBufferManager
    ///
    /// @brief  Create image buffer manager
    ///
    /// @param  pBufferManagerName       Name of the image buffer manager
    /// @param  pBufferManagerCreateData Buffer manager create data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    static CamxResult CreateImageBufferManager(
        const CHAR*              pBufferManagerName,
        BufferManagerCreateData* pBufferManagerCreateData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// FillTuningModeData
    ///
    /// @brief  Fill tuning mode data for process request
    ///
    /// @param  ppTuningModeData Pointer to fill with pointer to tuning mode data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult FillTuningModeData(
        VOID** ppTuningModeData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// EnableOutputPortForStreams
    ///
    /// @brief  Enable output port for some stream
    ///
    /// @param  outputPortIndex Output port that needs to be enabled for the passed in stream
    /// @param  streamIdMask    Streams to enable
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID EnableOutputPortForStreams(
        UINT outputPortIndex,
        UINT streamIdMask)
    {
        CAMX_ASSERT(outputPortIndex < m_outputPortsData.numPorts);

        OutputPort* pOutputPort = &m_outputPortsData.pOutputPorts[outputPortIndex];

        pOutputPort->enabledInStreamMask |= streamIdMask;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DisableOutputPortForStream
    ///
    /// @brief  Disable output port for some stream
    ///
    /// @param  outputPortIndex Output port that needs to be disabled for the passed in stream
    /// @param  streamId        Stream to enable
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE VOID DisableOutputPortForStream(
        UINT outputPortIndex,
        UINT streamId)
    {
        CAMX_ASSERT(outputPortIndex < m_outputPortsData.numPorts);

        OutputPort* pOutputPort = &m_outputPortsData.pOutputPorts[outputPortIndex];

        pOutputPort->enabledInStreamMask = Utils::BitReset(pOutputPort->enabledInStreamMask, streamId);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsOutputPortEnabledForStream
    ///
    /// @brief  Is output port enabled for some stream
    ///
    /// @param  outputPortIndex Output port to check
    /// @param  streamId        Stream to check for
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsOutputPortEnabledForStream(
        UINT outputPortIndex,
        UINT streamId
        ) const
    {
        CAMX_ASSERT(outputPortIndex < m_outputPortsData.numPorts);

        OutputPort* pOutputPort = &m_outputPortsData.pOutputPorts[outputPortIndex];

        return Utils::IsBitSet(pOutputPort->enabledInStreamMask, streamId);
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsOutputPortEnabled
    ///
    /// @brief  Check if output port is enabled
    ///
    /// @param  outputPortIndex Outputport to check
    ///
    /// @return TRUE if enabled, FALSE if disabled
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsOutputPortEnabled(
        UINT outputPortIndex
        ) const
    {
        CAMX_ASSERT(outputPortIndex < m_outputPortsData.numPorts);

        OutputPort* pOutputPort = &m_outputPortsData.pOutputPorts[outputPortIndex];

        return pOutputPort->flags.isEnabled;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsInputPortEnabled
    ///
    /// @brief  Check if input port is enabled
    ///
    /// @param  inputPortIndex Inputport to check
    ///
    /// @return TRUE if enabled, FALSE if disabled
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsInputPortEnabled(
        UINT inputPortIndex
        ) const
    {
        CAMX_ASSERT(inputPortIndex < m_inputPortsData.numPorts);

        InputPort* pInputPort = &m_inputPortsData.pInputPorts[inputPortIndex];

        return pInputPort->flags.isEnabled;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WriteData
    ///
    /// @brief  Write data to the data pools and publish it
    ///
    /// @param  requestId Request for which data is being updated
    /// @param  dataId    Tag or Property being updated
    /// @param  size      Size of data to update, sizeof(struct) for properties, number or elements for tags
    /// @param  pData     Pointer to data to set in the pool
    ///
    /// @return CamxResult
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult WriteData(
        UINT64      requestId,
        UINT32      dataId,
        SIZE_T      size,
        const VOID* pData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// IsNodeEnabled
    ///
    /// @brief  Check if the node is enabled
    ///
    /// @return TRUE if enabled, FALSE if disabled
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CAMX_INLINE BOOL IsNodeEnabled() const
    {
        return m_nodeFlags.isEnabled;
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// RecycleRetiredCmdBuffers
    ///
    /// @brief  Evaluate retired cmdbuffers list and recycle retired ones
    ///
    /// @param  requestId Request for which cmdbuffers are complete
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID RecycleRetiredCmdBuffers(
        UINT64 requestId);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetupRequestInputPorts
    ///
    /// @brief  Perform the setup of input ports for a new request
    ///
    /// @param  pPerBatchedFrameInfo Per batch information for the request
    ///
    /// @return Status of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult SetupRequestInputPorts(
        PerBatchedFrameInfo* pPerBatchedFrameInfo);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetupRequestOutputPorts
    ///
    /// @brief  Perform the setup of output ports for a new request
    ///
    /// @param  pPerBatchedFrameInfo Per batch information for the request
    ///
    /// @return Status of operation
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult SetupRequestOutputPorts(
        PerBatchedFrameInfo* pPerBatchedFrameInfo);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetNumOfBuffersToBeAllocatedImmediately
    ///
    /// @brief  Get the number of buffers to be allocated immediately during the call to InitializeBuffers in the
    ///         ImageBufferManager. For certain nodes, a small subset of the total buffers needed are allocated immediately
    ///         and the remainder are allocated later if needed
    ///
    /// @param  immediateBufferCount    ImmediateAllocCount defined in xml bufferProperties
    /// @param  maxBufferCount          Maximum buffer count to use when override buffer count is enabled and set to 0
    ///
    /// @return Number of buffers to be allocated immediately
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetNumOfBuffersToBeAllocatedImmediately(
        UINT immediateBufferCount,
        UINT maxBufferCount);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// GetMaximumNumOfBuffersToBeAllocated
    ///
    /// @brief  Get the maximum number of buffers to be allocated in the ImageBufferManager. If the override value is set, the
    ///         maximum buffer count value (as determined by the value inside buffer properties) is overriden with this value
    ///
    /// @param  maxBufferCount Maximum buffer count to use when override buffer count is enabled and set to 0
    ///
    /// @return Maximum number of buffers to be allocated
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    UINT GetMaximumNumOfBuffersToBeAllocated(
        UINT maxBufferCount);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// DumpData
    ///
    /// @brief  Helper function to dump the output of a Node
    ///
    /// @param  pFenceHandlerData Pointer to fence handler data
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID DumpData(
        NodeFenceHandlerData* pFenceHandlerData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// AddInputConnectedforBypass
    ///
    /// @brief  Add number of input connected through to this output port
    ///
    /// @param  outputPortIndex         output port index
    /// @param  numInputPortsConnected  num of input ports connected through bypass
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    VOID AddInputConnectedforBypass(
        UINT outputPortIndex,
        UINT numInputPortsConnected);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// UpdateBufferInfoforPendingInputPorts
    ///
    /// @brief  Update buffer info for pending input ports
    ///
    /// @param  pRequestPorts Info of all active ports
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult UpdateBufferInfoforPendingInputPorts(
        PerRequestActivePorts* pRequestPorts);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// SetBufferDependency
    ///
    /// @brief  Set buffer dependency for the node that has bypassable parent node
    ///
    /// @param  pExecuteProcessRequestData Process Request data
    ///
    /// @return CamxResultSuccess if successful
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    CamxResult SetBufferDependency(
        ExecuteProcessRequestData* pExecuteProcessRequestData);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// UpdateDeviceIndices
    ///
    /// @brief  Update device indices
    ///
    /// @param  outputPortIndex output port index
    /// @param  pDeviceIndices  pointer to the devices that needs to be added
    /// @param  deviceCount     device indices count
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID UpdateDeviceIndices(
        UINT         outputPortIndex,
        const INT32* pDeviceIndices,
        UINT         deviceCount);

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /// WatermarkImage
    ///
    /// @brief  Helper function to watermark frame id onto frame
    ///
    /// @param  pFenceHandlerData Pointer to fence handler data
    ///
    /// @return None
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    VOID WatermarkImage(
        NodeFenceHandlerData* pFenceHandlerData);

    Node(const Node&) = delete;                                       ///< Disallow the copy constructor
    Node& operator=(const Node&) = delete;                            ///< Disallow assignment operator

    NodeFlags              m_nodeFlags;                                ///< Node flags
    UINT                   m_nodeType;                                 ///< Node type
    UINT                   m_instanceId;                               ///< Node instance id
    CHAR                   m_nodeNameInstanceId[MaxStringLength64];    ///< Node name and instance id
    UINT                   m_pipelineNodeIndex;                        ///< This instance's index in the array of pipeline nodes
    AllOutputPortsData     m_outputPortsData;                          ///< Node output port data - Do not remove from private
    AllInputPortsData      m_inputPortsData;                           ///< Node input port data - Do not remove from private
    Pipeline*              m_pPipeline;                                ///< Pipeline object pointer
    DeferredRequestQueue*  m_pDRQ;                                     ///< DRQ pointer
    INT32                  m_deviceIndices[CamxMaxDeviceIndex];        ///< Array of device indices
                                                                       /// that is acquired by this node
    UINT                   m_cslDeviceCount;                           ///< The number of rt devices acquired by this node
    CSLDeviceHandle        m_hCSLDeviceHandles[CamxMaxDeviceIndex];    ///< Array of CSL device handle to be linked

    MetadataPool*          m_pInputPool;                               ///< Pointer to input metadata pool

    MetadataPool*          m_pMainPool;                                ///< Pointer to main metadata/property pool
    MetadataPool*          m_pEarlyMainPool;                           ///< Pointer to main metadata/property pool
    MetadataPool*          m_pInternalPool;                            ///< Pointer to internal property pool
    MetadataPool*          m_pUsecasePool;                             ///< Pointer to per usecase property pool
    MetadataPool*          m_pDebugDataPool;                           ///< Pointer to Debug-data metadata pool
    ThreadManager*         m_pThreadManager;                           ///< Pointer to Thread Manager
    UINT                   m_deviceIndexCount;                         ///< The number of devices acquired by this node
    CmdBufferManager**     m_ppCmdBufferManagers;                      ///< Array of cmd managers,allocated by subclassed HW
                                                                       ///  node
    UINT                   m_numCmdBufferManagers;                     ///< Number of cmd managers in m_pCmdManagers
    UINT                   m_maxNumCmdBufferManagers;                  ///< Max require number of command buffer managers
    NodePerRequestInfo     m_perRequestInfo[MaxRequestQueueDepth];     ///< Per request info
    UINT                   m_maxOutputPorts;                           ///< Max output ports(provided by derived node class)
    UINT                   m_maxInputPorts;                            ///< Max input ports(provided by derived node class)
    JobHandle              m_hThreadJobFamilyHandle;                   ///< Handle to the registered job family.
    BufferNegotiationData  m_bufferNegotiationData;                    ///< BufferNegotiation data
    ChiContext*            m_pChiContext;                              ///< Chi Context pointer
    HwContext*             m_pHwContext;                               ///< HwContext pointer
    ExternalComponentInfo  m_nodeExtComponents[MaxExternalComponents]; ///< Node external component name
    UINT                   m_nodeExtComponentCount;                    ///< Node external component count

    /// @todo (CAMX-2905)  Optimize all nodes to be re-entrant
    Mutex*                 m_pProcessRequestLock;                      ///< Mutex to protect node execution state
    Mutex*                 m_pBufferRequestLock;                       ///< Mutex to protect buffer request and release
    Mutex*                 m_pBufferReleaseLock;                       ///< Mutex to protect buffer state
    Mutex*                 m_pFenceCreateReleaseLock;                  ///< Mutex to protect node fence create/release state
    UINT64                 m_CSLSyncID[MaxRequestBufferDepth];         ///< CSl SyncID to syncrhrinuze links in CRM
    WatermarkPattern*      m_pWatermarkPattern;                        ///< Contains the info to watermark the buffer
    BOOL                   m_bHasLoopBackPorts;                        ///< Indicate if node has loopback ports

    CAMX_TLS_STATIC_CLASS_DECLARE(UINT64, m_tRequestId);               ///< Thread request id
};

CAMX_NAMESPACE_END

#endif // CAMXNODE_H
